package PropertiesUtils

import (
	"strings"
	"os"
	"bufio"
	"io"
	"time"
	"strconv"
	"fmt"
)

/**
核心配置结构，层级为：
文件路径->node->key->value
文件路径可为本地路径或者远程路径
 */
var properties = make(map[string]map[string]map[string]valueStruct)

var DEFAULT_PROPERTIESFILE="application.properties"

type valueStruct struct {
	key string
	value interface{}
	intime int64
	outtime int64
}

var propexpiretime = 0;


func initFileConfig(path string)(map[string]map[string]valueStruct,error) {
	var filemap = make(map[string]map[string]valueStruct)

	f, err := os.Open(path)
	if err != nil {
		return filemap,err
	}
	defer f.Close()

	r := bufio.NewReader(f)
	var currNode = ""
	for {
		b, _, err := r.ReadLine()
		if err != nil {
			if err == io.EOF {
				break
			}
			return filemap,err
		}
		s := strings.TrimSpace(string(b))
		//fmt.Println(s)
		if strings.Index(s, "#") == 0 {
			continue
		}
		n1 := strings.Index(s, "[")
		n2 := strings.LastIndex(s, "]")
		if n1 ==0 && n2 > -1 && n2 > n1+1 {
			currNode = strings.TrimSpace(s[n1+1 : n2])
			continue
		}

		if len(currNode) == 0 {
			continue
		}
		index := strings.Index(s, "=")
		if index < 0 {
			continue
		}

		key := strings.TrimSpace(s[:index])
		if len(key) == 0 {
			continue
		}
		value := strings.TrimSpace(s[index+1:])

		pos := strings.Index(value, "\t#")
		if pos > -1 {
			value = value[0:pos]
		}

		pos = strings.Index(value, " #")
		if pos > -1 {
			value = value[0:pos]
		}

		pos = strings.Index(value, "\t//")
		if pos > -1 {
			value = value[0:pos]
		}

		pos = strings.Index(value, " //")
		if pos > -1 {
			value = value[0:pos]
		}
		if(currNode=="properties"){
			if(key=="propexpiretime"){
				propexpiretime,err = strconv.Atoi(value)
				if(err!=nil){
					fmt.Println("配置加载异常,配置文件中的propexpiretime解析不正确")
					panic(err)
				}
			}
		}
		var v = valueStruct{key:key,value:value,intime:time.Now().Unix(),outtime:-1}

		if(filemap[currNode]==nil){
			filemap[currNode]=make(map[string]valueStruct)
		}
		filemap[currNode][key]=v
	}
	return filemap,nil
}


func GetValue(path string,node string,key string)(string,bool){
	if(properties[path]==nil){
		var filemap,err = initFileConfig(path);
		if(err!=nil){
			//如果需要配置读取错误则报错，此处注释打开
			//panic(err)
		}
		properties[path]=filemap
	}
	var nodeMap = properties[path][node]
	var valueStruct = nodeMap[key]

	if(valueStruct.outtime==-1&&(valueStruct.intime+int64(propexpiretime))<time.Now().Unix()){
		//如果是配置文件中的文件，发现其中一个配置的过期时间已经超过了propexpiretime，则重新加载配置
		//重新初始化再获取
		var filemap,err = initFileConfig(path);
		if(err!=nil){
			//如果需要配置读取错误则报错，此处注释打开
			//panic(err)
		}
		properties[path]=filemap
		return GetValue(path,node,key)
	}else if(valueStruct.outtime!=-1&&valueStruct.outtime<time.Now().Unix()){
		//如果不是配置文件中的文件，发现其中一个配置的valueStruct.outtime小于当前系统时间，则该节点过期
		delete(nodeMap, key)
		return "",false
	}else{
		//未过期
		return valueStruct.value.(string),true
	}
}
func GetInterfaceValue(path string,node string,key string)(interface{},bool){
	if(properties[path]==nil){
		var filemap,err = initFileConfig(path);
		if(err!=nil){
			//如果需要配置读取错误则报错，此处注释打开
			//panic(err)
		}
		properties[path]=filemap
	}
	var nodeMap = properties[path][node]
	var valueStruct = nodeMap[key]

	if(valueStruct.outtime<time.Now().Unix()){
		//已过期
		delete(nodeMap, key)
		return "",false
	}else{
		//未过期
		return valueStruct.value,true
	}
}
func SetValue(path string,node string,key string,value string,expiresecond int64)(bool){
	if(properties[path]==nil){
		properties[path]=make(map[string]map[string]valueStruct)
	}
	var nodeMap = properties[path][node]

	if(nodeMap==nil){
		nodeMap = make(map[string]valueStruct)
		properties[path][node] = nodeMap
	}
	var intime = time.Now().Unix()
	var outtime = intime + expiresecond
	var vs = valueStruct{key:key,value:value,intime:intime,outtime:outtime}
	nodeMap[key]=vs
	return true
}
func SetInterfaceValue(path string,node string,key string,value interface{},expiresecond int64)(bool){
	if(properties[path]==nil){
		properties[path]=make(map[string]map[string]valueStruct)
	}
	var nodeMap = properties[path][node]

	if(nodeMap==nil){
		nodeMap = make(map[string]valueStruct)
		properties[path][node] = nodeMap
	}
	var intime = time.Now().Unix()
	var outtime = intime + expiresecond
	var vs = valueStruct{key:key,value:value,intime:intime,outtime:outtime}
	nodeMap[key]=vs
	return true
}
func GetConfig(node string,key string,defaultvalue string)(string,bool){
	v,found := GetValue("application.properties",node,key)
	if(found){
		return v,true
	}else{
		return defaultvalue,false
	}
}